package com.icinfo.cloud.provider.punish.common.sign.service.impl;

import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import com.icinfo.cloud.provider.common.constant.Constant;
import com.icinfo.cloud.provider.common.utils.BaseUtil;
import com.icinfo.cloud.provider.common.utils.fadu.DESCoderHelper;
import com.icinfo.cloud.provider.common.utils.fadu.HttpClientUtil;
import com.icinfo.cloud.provider.common.utils.fadu.SignUtils;
import com.icinfo.cloud.provider.punish.common.sign.dto.FaduSignAttachmentFileSaveDto;
import com.icinfo.cloud.provider.punish.common.sign.service.IFaduSignService;
import com.icinfo.cloud.provider.punish.csource.manage.mapper.CaseSourceMaterialRecordMapper;
import com.icinfo.cloud.provider.punish.csource.manage.model.CaseSourceMaterialRecord;
import com.icinfo.cloud.provider.punish.csource.manage.service.ICaseSourceMaterialRecordService;
import com.icinfo.cloud.provider.punish.ucase.casemain.enums.AttachmentTypeEnum;
import com.icinfo.cloud.provider.punish.ucase.casemain.model.CaseAppendixRecord;
import com.icinfo.cloud.provider.punish.ucase.casemain.service.ICaseAppendixRecordService;
import com.icinfo.framework.core.exception.BusinessException;
import com.icinfo.framework.tools.utils.StringUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.*;
import java.time.LocalDateTime;
import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

/**
 * 法度签字文件接口调用
 *
 * @Author lvzhenzhao
 * @Date 2022/3/8 11:03
 **/
@Slf4j
@Service
public class FaduSignServiceImpl implements IFaduSignService {

    //0为不加密，默认值为0,1为请求参数加密，2为返回值加密，3为请求/返回双向加密
    public static final String EncryptNo = "0";
    public static final String EncryptRequest = "1";
    public static final String EncryptReturn = "2";
    public static final String EncryptAll = "3";

    //常量1 true
    public final static String YES = "1";

    /**
     * 法度服务地址
     */
    @Value("${fadu-server.url}")
    private String url;

    /**
     * 法度appKey
     */
    @Value("${fadu-server.appKey}")
    private String appKey;

    /**
     * 法度appSecret
     */
    @Value("${fadu-server.appSecret}")
    private String appSecret = "";
    /**
     * 法度getSignVideo
     */
    @Value("${fadu-server.api.getSignVideo}")
    private String getSignVideo;
    /**
     * getSignZip
     */
    @Value("${fadu-server.api.getSignZip}")
    private String getSignZip;
    @Value("${document.url}")
    private String docServerUrl;

    @Value("${document.api.uploadBase64File}")
    private String uploadBase64File;
    @Resource
    private ICaseAppendixRecordService caseAppendixRecordService;
    @Resource
    private CaseSourceMaterialRecordMapper caseSourceMaterialRecordMapper;
    @Resource
    private ICaseSourceMaterialRecordService caseSourceMaterialRecordService;
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void getSignVideo(String evidenceId, String requestId, String createUser) {
        JSONObject jsonObject;
        JSONObject paramsJo = new JSONObject();
        paramsJo.put("requestId", requestId);
        try {
            jsonObject = this.sendRequest("getSignVideo", paramsJo, "", "", url + getSignVideo);
        } catch (Exception e) {
            log.error("调取第三方接口获取签字视频失败,requestId:{},{}", requestId, e);
            throw new BusinessException("调取第三方接口获取签字视频失败");
        }

        if ("0".equals(jsonObject.getString("resultCode"))) {
            JSONObject results = jsonObject.getJSONObject("results");
            if (Objects.nonNull(results) && !StringUtils.isEmpty(results.getString("base64Str"))) {
                //      this.unCompressAndUpload(evidenceId, results.getString("base64Str"), createUser);
            } else {
                log.error("获取签字视频失败,requestId:{}, result:{}", requestId, jsonObject);
                throw new BusinessException("获取签字视频失败");
            }
        } else {
            log.error("获取签字文件失败,requestId:{}, result:{}", requestId, jsonObject);
            throw new BusinessException("获取签字视频失败");
        }
    }

//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSignZip(FaduSignAttachmentFileSaveDto saveDto, String requestId) throws Exception {
        JSONObject jsonObject = new JSONObject();
        JSONObject paramsJo = new JSONObject();
        paramsJo.put("requestId", requestId);
        try {
            jsonObject = this.sendRequest("getSignZip", paramsJo, "", "", url + getSignZip);
        } catch (Exception e) {
            log.error("调取第三方接口获取签字文件失败,requestId:{},{}", requestId, e);
            throw new BusinessException("调取第三方接口获取签字文件失败");
        }
        if ("0".equals(jsonObject.getString("resultCode"))) {
            JSONObject results = jsonObject.getJSONObject("results");
            if (Objects.nonNull(results) && !StringUtils.isEmpty(results.getString("base64Str"))) {
                if ("1".equals(saveDto.getBusinessType())) {
                    //删除原来的签字捺印附件
                    Map<String, Object> map = new HashMap<>();
                    map.put("caseId", saveDto.getWorkId());
                    map.put("documentCatalogCode", saveDto.getDocCategoryCode());
                    map.put("partyId", saveDto.getPartyId());
                    map.put("appendixTypeId", "SIGN_ATTACHMENT");
                    caseAppendixRecordService.removeCaseAppendixRecordByAppendixTypeId(map);
                    //解压并保存其他签字捺印附件
                    this.unCompressAndUploadForCase(saveDto, results.getString("base64Str"));
                }
                if ("2".equals(saveDto.getBusinessType())) {
                    unCompressAndUploadForCaseSource(saveDto, results.getString("base64Str"));
                }


            } else {
                log.error("获取签字文件失败,requestId:{}, result:{}", requestId, jsonObject);
                throw new BusinessException("获取签字文件失败");
            }
        } else {
            log.error("获取签字文件失败,requestId:{}, result:{}", requestId, jsonObject);
            throw new BusinessException("获取签字文件失败");
        }
    }
//    @Transactional(rollbackFor = Exception.class)
    @Override
    public void saveSignZipForCaseSource(FaduSignAttachmentFileSaveDto saveDto, String requestId) throws Exception {
        JSONObject jsonObject = new JSONObject();
        JSONObject paramsJo = new JSONObject();
        paramsJo.put("requestId", requestId);
        try {
            jsonObject = this.sendRequest("getSignZip", paramsJo, "", "", url + getSignZip);
        } catch (Exception e) {
            log.error("调取第三方接口获取签字文件失败,requestId:{},{}", requestId, e);
            throw new BusinessException("调取第三方接口获取签字文件失败");
        }
        if ("0".equals(jsonObject.getString("resultCode"))) {
            JSONObject results = jsonObject.getJSONObject("results");
            if (Objects.nonNull(results) && !StringUtils.isEmpty(results.getString("base64Str"))) {
                this.unCompressAndUpload(saveDto, results.getString("base64Str"));
            } else {
                log.error("获取签字文件失败,requestId:{}, result:{}", requestId, jsonObject);
                throw new BusinessException("获取签字文件失败");
            }
        } else {
            log.error("获取签字文件失败,requestId:{}, result:{}", requestId, jsonObject);
            throw new BusinessException("获取签字文件失败");
        }
    }
    @Override
    public void getSignZipDemo(String requestId) {
        JSONObject jsonObject;
        JSONObject paramsJo = new JSONObject();
        paramsJo.put("requestId", requestId);
        try {
            jsonObject = this.sendRequest("getSignZip", paramsJo, "", "", url + getSignZip);
        } catch (Exception e) {
            log.error("调取第三方接口获取签字文件失败,requestId:{},{}", requestId, e);
            throw new BusinessException("调取第三方接口获取签字文件失败");
        }
        String jsonString = jsonObject.toJSONString();
        String substring = jsonString.substring(0, jsonString.length() < 200 ? jsonString.length() : 200);
        if ("0".equals(jsonObject.getString("resultCode"))) {
            JSONObject results = jsonObject.getJSONObject("results");
            if (Objects.nonNull(results) && !StringUtils.isEmpty(results.getString("base64Str"))) {
                log.info("获取签字文件成功:{}", substring);
            } else {
                log.error("获取签字文件失败,requestId:{}, result:{}", requestId, substring);
                throw new BusinessException("获取签字文件失败");
            }
        } else {
            log.error("获取签字文件失败,requestId:{}, result:{}", requestId, substring);
            throw new BusinessException("获取签字文件失败");
        }
    }

    /**
     * 解压并上传解压出来的文件(不包含PDF)
     *
     * @param saveDto   保存dto
     * @param base64Str
     * @author shishengyao
     * @date 2022/11/18
     */
    private void unCompressAndUpload(FaduSignAttachmentFileSaveDto saveDto, String base64Str) throws IOException {
        BufferedOutputStream stream = null;

        try {
            File file = File.createTempFile("file", "zip");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            stream = new BufferedOutputStream(fileOutputStream);

            Base64.Decoder decoder = Base64.getDecoder();
            byte[] bytes = decoder.decode(base64Str);
            stream.write(bytes);

            //创建压缩文件对象
            ZipFile zipFile = new ZipFile(file);
            //开始解压
            Enumeration<?> entries = zipFile.entries();
            //判断是否获取到签字视频
            boolean flag = false;
            //     List<EvidenceFile> fileList = new ArrayList<>();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 如果是文件夹，就创建个文件夹
                if (!entry.isDirectory()) {
                    String prefix = entry.getName().substring(entry.getName().lastIndexOf("."));
                    String suffix = entry.getName().substring(entry.getName().lastIndexOf("."));
                    //目前只保存签字视频和签字轨迹
                    if (".mp4".equalsIgnoreCase(suffix) || ".xml".equalsIgnoreCase(suffix)) {
                        // 将压缩文件内容写入到这个文件中
                        InputStream is = zipFile.getInputStream(entry);
                        String fileName = BaseUtil.createUid() + suffix;
                       // String url = saveFileToOss(is, fileName, suffix.replace(".", ""));


                    }
                    if (".mp4".equalsIgnoreCase(suffix)) {
                        flag = true;
                    }
                }
            }
            if (!flag) {
                throw new BusinessException("没有获取到签字视频,签字失败");
            }
        } catch (Exception e) {
            log.error("解压zip文件失败,base64Str:{},{}", base64Str, e);
            throw new BusinessException("解压签字文件失败");
        } finally {
            stream.close();
        }

    }

    /**
     * 描述：解压并保存其他签字捺印附件
     *
     * @param saveDto   保存dto
     * @param base64Str base64 str
     * @author shishengyao
     * @date 2023/03/15
     */
    private void unCompressAndUploadForCase(FaduSignAttachmentFileSaveDto saveDto, String base64Str) throws IOException {
        BufferedOutputStream stream = null;

        try {
            File file = File.createTempFile("file", "zip");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            stream = new BufferedOutputStream(fileOutputStream);

            Base64.Decoder decoder = Base64.getDecoder();
            byte[] bytes = decoder.decode(base64Str);
            stream.write(bytes);

            //创建压缩文件对象
            ZipFile zipFile = new ZipFile(file);
            //开始解压
            Enumeration<?> entries = zipFile.entries();
            //判断是否获取到签字视频
            boolean flag = false;
            //     List<EvidenceFile> fileList = new ArrayList<>();
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 如果是文件夹，就创建个文件夹
                if (!entry.isDirectory()) {
                    String fileFullName = entry.getName();
                    String suffix = entry.getName().substring(entry.getName().lastIndexOf(Constant.STRING_POINT));
                    String prefix = entry.getName().substring(0,fileFullName.lastIndexOf(Constant.STRING_POINT));
                    //目前只保存签字视频和签字轨迹
                    if (".mp4".equalsIgnoreCase(suffix) || ".xml".equalsIgnoreCase(suffix)) {
                        // 将压缩文件内容写入到这个文件中
                        InputStream is = zipFile.getInputStream(entry);
                        byte[] dateStream = BaseUtil.readStream(is);
                        String suffixFileType=suffix.replace(".","");
                        String url = saveFileToOss(dateStream,fileFullName, suffixFileType);
                        CaseAppendixRecord caseAppendixRecord = new CaseAppendixRecord();
                        String materialTypeId=".mp4".equalsIgnoreCase(suffix) ? AttachmentTypeEnum.SIGN_ATTACHMENT_01.getCode():AttachmentTypeEnum.SIGN_ATTACHMENT_02.getCode();
                        //设置当事人id
                        caseAppendixRecord.setPartyId(saveDto.getPartyId());
                        caseAppendixRecord.setCaseId(saveDto.getWorkId());
                        caseAppendixRecord.setAppendixTypeId(materialTypeId);
                        caseAppendixRecord.setAppendixName(fileFullName);
                        caseAppendixRecord.setAppendixNamePrefix(prefix);
                        caseAppendixRecord.setAppendixNameSuffix(suffixFileType);
                        caseAppendixRecord.setAppendixUrl(url);
                        caseAppendixRecord.setDocumentCatalogCode(saveDto.getDocCategoryCode());
                        caseAppendixRecord.setUploadTime(LocalDateTime.now());
                        caseAppendixRecordService.saveCaseAppendixRecord(caseAppendixRecord);
                    }
                    if (".mp4".equalsIgnoreCase(suffix)) {
                        flag = true;
                    }
                }
            }
            if (!flag) {
                throw new BusinessException("没有获取到签字视频,签字失败");
            }
        } catch (Exception e) {
            log.error("解压zip文件失败,base64Str:{},{}", base64Str, e);
            throw new BusinessException("解压签字文件失败");
        } finally {
            stream.close();
        }

    }


    /**
     * .net报表服务请求调用方法
     *
     * @param function    接口名
     * @param paramsJo    参数
     * @param encrypt     加密方式
     * @param compression 压缩方式
     * @return
     * @throws Exception
     */
    public JSONObject sendRequest(String function, JSONObject paramsJo, String encrypt, String compression, String url) throws Exception {
        //获取配置
        //密钥
        String _appSecret = appSecret;
        //key
        String _appKey = appKey;
        Map<String, String> params = new HashMap<>();
        if (encrypt == null || "".equals(encrypt.trim())) {
            encrypt = EncryptNo;
        }
        if (compression == null || "".equals(compression.trim())) {
            compression = YES;
        }
        String paramsJoStr = paramsJo.toString();
        if (EncryptRequest.equals(encrypt) || EncryptAll.equals(encrypt)) {
            paramsJoStr = DESCoderHelper.getInstance().encryptNetString(paramsJo.toJSONString(), _appSecret);
        }
        params.put("params", paramsJoStr);
        params.put("app_key", _appKey);

        params.put("encrypt", encrypt);
        //那三个
        params.put("function", function);
        params.put("compress", compression);
        params.put("sign", SignUtils.signRequest(params, _appSecret));
        log.error("===========调取法度接口获取签字文件开始,requestParam:{},requestUrl:{}", JSONObject.toJSONString(params),url);
        String resultStr = HttpClientUtil.postForm(url, params);
        log.info("===========调取第三方接口获取签字文件接口，结果返回：{}" , (resultStr.length() > 500 ? resultStr.substring(0, 500) : resultStr));
        //如果返回数据压缩了，进行解压缩
        if (YES.equals(compression)) {
            resultStr = unCompress(resultStr);
        }
        JSONObject result = JSON.parseObject(resultStr);
        if (!"0".equals(result.getString("resultCode"))) {
            log.error("===========调取第三方接口获取签字文件接口解析返回结果：{}" , resultStr);
            throw new RuntimeException(result.getString("resultMsg"));
        }
        String resData = result.getString("results");
        //如果返回数据加密了，进行解密
        if (EncryptReturn.equals(encrypt) || EncryptAll.equals(encrypt)) {
            resData = DESCoderHelper.decryptNetString(resData, _appSecret);
        }
        result.put("results", resData);
        return result;
    }

    /**
     * 对字符串进行解压缩
     *
     * @param str
     * @return
     * @throws IOException
     */
    public static String unCompress(String str) throws IOException {
        if (str == null || str.length() == 0) {
            return "";
        }
        byte[] t = com.icinfo.cloud.provider.common.utils.fadu.Base64.decodeBase64(str);
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        ByteArrayInputStream in = new ByteArrayInputStream(t);
        GZIPInputStream gunzip = new GZIPInputStream(in);
        try {
            byte[] buffer = new byte[256];
            int n;
            while ((n = gunzip.read(buffer)) >= 0) {
                out.write(buffer, 0, n);
            }
        } finally {
            gunzip.close();
            in.close();
            out.close();
        }
        return out.toString("UTF-8");
    }

    /**
     * 描述：将文件上传到oss
     *
     * @param bytes    字节
     * @param fileName 文件名称
     * @param fileType 文件类型
     * @return {@link String }
     * @author shishengyao
     * @date 2022/11/18
     */
    private String saveFileToOss( byte[] bytes, String fileName, String fileType) {
        JSONObject jsonObject = new JSONObject();
        jsonObject.put("fileBytes", bytes);
        jsonObject.put("fileType", fileType);
        jsonObject.put("fileName", fileName);
        JSONObject parseObject = JSON.parseObject(HttpUtil.post(docServerUrl + uploadBase64File, jsonObject.toString()));
        String cd = "code";
        int th = 200;
        String url = "";
        if (parseObject.getInteger(cd) == th) {
            url = parseObject.getJSONObject("data").getString("ossUrl");
            log.info("uploadInputStream url:{}", url);
        } else {
            log.info("warn receive sign file upload oss fail,result:{}", parseObject.toString());
            throw new com.icinfo.cloud.provider.common.exception.BusinessException("文件上传时出现异常-receiveSignDoc");
        }
        return url;
    }


    /**
     * 描述：解压并上传解压出来的文件(不包含PDF) 案源文书
     *
     * @param saveDto   保存dto
     * @param base64Str
     * @author shishengyao
     * @date 2022/11/18
     */
    private void unCompressAndUploadForCaseSource(FaduSignAttachmentFileSaveDto saveDto, String base64Str) throws IOException {
        BufferedOutputStream stream = null;
        try {
            File file = File.createTempFile("file", "zip");
            FileOutputStream fileOutputStream = new FileOutputStream(file);
            stream = new BufferedOutputStream(fileOutputStream);

            Base64.Decoder decoder = Base64.getDecoder();
            byte[] bytes = decoder.decode(base64Str);
            stream.write(bytes);

            //创建压缩文件对象
            ZipFile zipFile = new ZipFile(file);
            //开始解压
            Enumeration<?> entries = zipFile.entries();
            //判断是否获取到签字视频
            boolean flag = false;
            while (entries.hasMoreElements()) {
                ZipEntry entry = (ZipEntry) entries.nextElement();
                // 如果是文件夹，就创建个文件夹
                if (!entry.isDirectory()) {
                    String fileFullName = entry.getName();
                    String suffix = entry.getName().substring(entry.getName().lastIndexOf(Constant.STRING_POINT));
                    //目前只保存签字视频和签字轨迹
                    if (".mp4".equalsIgnoreCase(suffix) || ".xml".equalsIgnoreCase(suffix)) {
                        // 将压缩文件内容写入到这个文件中
                        InputStream is = zipFile.getInputStream(entry);
                        String suffixFileType=suffix.replace(".","");
                        byte[] fileBytes = BaseUtil.readStream(is);
                        String url = saveFileToOss(fileBytes, fileFullName, suffixFileType);
                        CaseSourceMaterialRecord caseSourceMaterialRecord = new CaseSourceMaterialRecord();
                        //设置当事人id
                        caseSourceMaterialRecord.setId(BaseUtil.createUid());
                        caseSourceMaterialRecord.setPartyId(saveDto.getPartyId());
                        caseSourceMaterialRecord.setCaseSourceId(saveDto.getWorkId());
                        String materialTypeId=".mp4".equalsIgnoreCase(suffix) ? AttachmentTypeEnum.SIGN_ATTACHMENT_01.getCode():AttachmentTypeEnum.SIGN_ATTACHMENT_02.getCode();
                        caseSourceMaterialRecord.setMaterialTypeId(materialTypeId);
                        caseSourceMaterialRecord.setMaterialName(fileFullName);
                        caseSourceMaterialRecord.setMaterialUrl(url);
                        caseSourceMaterialRecord.setDocumentCatalogCode(saveDto.getDocCategoryCode());
                        caseSourceMaterialRecord.setUploadTime(LocalDateTime.now());
                        caseSourceMaterialRecordMapper.insertSelective(caseSourceMaterialRecord);
                    }
                    if (".mp4".equalsIgnoreCase(suffix)) {
                        flag = true;
                    }
                }
            }
            if (!flag) {
                throw new BusinessException("没有获取到签字视频,签字失败");
            }
        } catch (Exception e) {
            log.error("解压zip文件失败,base64Str:{},{}", base64Str, e);
            throw new BusinessException("解压签字文件失败");
        } finally {
            stream.close();
        }

    }


}
